package com.company.cloud.acct.modules.app.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.company.cloud.acct.constant.AcctErrorEnum;
import com.company.cloud.acct.constant.AcctMsgSendTypeEnum;
import com.company.cloud.acct.modules.api.constant.AcctConstant;
import com.company.cloud.acct.modules.api.constant.AcctStateEnum;
import com.company.cloud.acct.modules.app.controller.req.BankCardAuthParam;
import com.company.cloud.acct.modules.app.controller.req.BankCardBindParam;
import com.company.cloud.acct.modules.app.controller.req.BankCardCodeParam;
import com.company.cloud.acct.modules.app.service.AcctBankCardService;
import com.company.cloud.acct.modules.base.entity.AccountInfo;
import com.company.cloud.acct.modules.base.entity.BankCardInfo;
import com.company.cloud.acct.modules.base.service.AccountInfoService;
import com.company.cloud.acct.modules.base.service.BankCardInfoService;
import com.company.cloud.acct.modules.cache.models.BankCardModel;
import com.company.cloud.acct.modules.cache.service.AcctCacheService;
import com.company.cloud.acct.modules.cache.utils.AccountCacheKeyUtils;
import com.company.cloud.acct.modules.cache.utils.AcctConvertUtils;
import com.company.cloud.acct.modules.sdk.bankfour.BankFourApi;
import com.company.cloud.acct.modules.sdk.bankfour.BankFourApiConfig;
import com.company.cloud.acct.modules.sdk.bankfour.enums.ApiCallReturnCodeEnum;
import com.company.cloud.acct.modules.sdk.bankfour.model.BankFourReq;
import com.company.cloud.acct.modules.sdk.bankfour.model.BankFourResp;
import com.company.cloud.common.asserts.ValidatorUtils;
import com.company.cloud.common.bean.LoginSimpleUserInfo;
import com.company.cloud.common.constant.BaseConstant;
import com.company.cloud.common.constant.BaseReturnEnum;
import com.company.cloud.common.exception.BusinessException;
import com.company.cloud.common.redis.service.RedisUtils;
import com.company.cloud.common.utils.CheckUtils;
import com.company.cloud.user.modules.api.service.UserDataRemoteService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

@Service
public class AcctBankCardServiceImpl implements AcctBankCardService {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private BankCardInfoService bankCardInfoService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private BankFourApiConfig bankFourApiConfig;
    @Autowired
    private AcctCacheService acctCacheService;
    @Autowired
    private UserDataRemoteService userDataRemoteService;
    @Autowired
    private AccountInfoService accountInfoService;



//    @Autowired
//    private JdbcTemplate jdbcTemplate;

//    @TxcTransaction(appName="wjj-test-01")
    @Override
    public void test(String str) {
        System.out.println("++++++++++++++++++++++++++++++++"+str);
//        jdbcTemplate.update("insert into user_money_a (id,money) values (3,200)");
//        jdbcTemplateA.update("update user_money_a set money = money - ? where id = 1", money);

//        System.out.println("GTS Transaction Begins: " + TxcContext.getCurrentXid());

        AccountInfo entity=new AccountInfo();
        entity.setCompanyNo("TP");
        entity.setUserId(Integer.parseInt(str));
        entity.setType("t");
        entity.setTotalFund(BigDecimal.ZERO);
        entity.setFund(BigDecimal.ZERO);
        entity.setFreezeFund(BigDecimal.ZERO);
        entity.setNotFund(BigDecimal.ZERO);
        entity.setState(AcctStateEnum.NORMAL.getCode());
//        entity.setCdt(LocalDateTime.now());
        entity.setCip("127.0.0.1");
        entity.setCman(1);
//        entity.setEdt(LocalDateTime.now());
        entity.setEip("127.0.0.1");
        entity.setEman(1);
        accountInfoService.save(entity);


//        BaseClientResponse<String> response = userDataRemoteService.wjjTest("ROLES_ADMIN");
//        if(!BaseReturnEnum.SUCCESS.getCode().equals(response.getReturnCode())){
//            System.out.println("+++++用户服务调用失败,事务回滚!");
//            throw new RuntimeException("用户服务调用失败,事务回滚!");
//        }

    }

    @Override
    public BankCardModel getBankCardDefByUser(Integer userId) {
        BankCardInfo entity = bankCardInfoService.getOne(new QueryWrapper<BankCardInfo>()
                .eq("user_id", userId)
                .eq("rows_state", BaseConstant.EnabledEnum.ENABLED.getCode())
                .eq("is_def", BaseConstant.YNEnum.YES.getCode())
        );
        if(entity!=null){
            return AcctConvertUtils.getBankCardModel(entity);
        }
        return null;
    }

    @Override
    public BankCardModel addBackCard(BankCardBindParam param, LoginSimpleUserInfo userInfo) {
        ValidatorUtils.validate(param);
        List<BankCardInfo> list = bankCardInfoService.list(new QueryWrapper<BankCardInfo>()
                .eq("card_no", param.getCardNo())
                .eq("card_user_name", param.getCardUserName())
                .eq("card_mobile", param.getCardMobile())
                .eq("card_id_card", param.getCardIdCard())
                .eq("rows_state", BaseConstant.EnabledEnum.ENABLED.getCode())
        );
        if (!CollectionUtils.isEmpty(list)) {
            throw new BusinessException(BaseReturnEnum.DATA_EXISTS);
        }
        BankCardInfo entity = AcctConvertUtils.getBankCardInfo(param);
        entity.setCompanyNo(userInfo.getCompanyNo());
        entity.setUserId(userInfo.getId());
        entity = bankfour(entity, userInfo);
        entity.addCreateParam(userInfo);
        entity.addEditParam(userInfo);
        bankCardInfoService.save(entity);

        if (BaseConstant.YNEnum.YES.getCode().equals(entity.getIsDef())) {
            bankCardInfoService.update(new UpdateWrapper<BankCardInfo>()
                    .eq("user_id", userInfo.getId())
                    .ne("id", entity.getId())
                    .set("is_def", BaseConstant.YNEnum.NO.getCode())
            );
        }
        acctCacheService.removeBankCardByUser(userInfo.getId());
        return AcctConvertUtils.getBankCardModel(entity);
    }

    @Override
    public void unbindBankCard(Integer bankCardId, LoginSimpleUserInfo userInfo) {
        BankCardInfo entity = bankCardInfoService.getById(bankCardId);
        if (null == entity) {
            throw new BusinessException(BaseReturnEnum.DATA_NOT_EXISTS);
        }
        if (!entity.getUserId().equals(userInfo.getId())) {
            throw new BusinessException(BaseReturnEnum.PARAM_ERROR);
        }
        entity.setRowsState(BaseConstant.EnabledEnum.DISABLED.getCode());
        entity.setIsDef(BaseConstant.YNEnum.NO.getCode());
        entity.addEditParam(userInfo);
        acctCacheService.removeBankCardByUser(userInfo.getId());
        bankCardInfoService.updateById(entity);
    }

    @Override
    public void updateDefBackCard(Integer bankCardId, LoginSimpleUserInfo userInfo) {
        BankCardInfo entity = bankCardInfoService.getById(bankCardId);
        if (null == entity) {
            throw new BusinessException(BaseReturnEnum.DATA_NOT_EXISTS);
        }
        if (!entity.getUserId().equals(userInfo.getId())) {
            throw new BusinessException(BaseReturnEnum.PARAM_ERROR);
        }
        entity.setIsDef(BaseConstant.YNEnum.YES.getCode());
        entity.addEditParam(userInfo);
        bankCardInfoService.updateById(entity);
        bankCardInfoService.update(new UpdateWrapper<BankCardInfo>()
                .eq("user_id", userInfo.getId())
                .ne("id", entity.getId())
                .set("is_def", BaseConstant.YNEnum.NO.getCode())
        );
        acctCacheService.removeBankCardByUser(userInfo.getId());
    }

    @Override
    public void checkBackCardAuth(BankCardAuthParam param, LoginSimpleUserInfo userInfo) {
        BankCardInfo entity = bankCardInfoService.getById(param.getId());
        if (null == entity) {
            throw new BusinessException(BaseReturnEnum.DATA_NOT_EXISTS);
        }
        if (!entity.getUserId().equals(userInfo.getId())) {
            throw new BusinessException(BaseReturnEnum.PARAM_ERROR);
        }
        if (AcctConstant.AuthState.AUTH_SUCCESS.getCode().equals(entity.getAuthState())) {
            throw new BusinessException(AcctErrorEnum.BANKCARD_AUTH);
        }
        validate(entity.getCardMobile(), param.getVcode(), userInfo);
        entity = bankfour(entity, userInfo);
        entity.addEditParam(userInfo);
        bankCardInfoService.updateById(entity);
    }

    @Override
    public void sendBankCardCode(BankCardCodeParam param, LoginSimpleUserInfo userInfo) {
        checkSendLimit(userInfo.getId(), param.getMobile());
        String vkey = AccountCacheKeyUtils.getVCodeKey(userInfo.getId(), param.getMobile());
        String vcode = RandomUtil.randomNumbers(4);
        redisUtils.mput(vkey, vcode, vcode,600);

        String content = getSmsContent(vcode, AcctMsgSendTypeEnum.BankCard_VCode);
        logger.info(content);
        // 发送短信
//        SimpleMessageReq simpleMessageReq = getMsgParam(param.getMobile(), userInfo.getId(), content);
//        BaseClientResponse response = messageSMSRemoteService.sendSmsNotTmpl(simpleMessageReq);
//        if (!BaseReturnEnum.SUCCESS.getCode().equals(response.getReturnCode())) {
//            throw new BusinessException(response.getReturnCode(), response.getReturnMsg());
//        }
    }

    @Override
    public void validate(String mobile, String vcode, LoginSimpleUserInfo userInfo) {
        String vkey = AccountCacheKeyUtils.getVCodeKey(userInfo.getId(), mobile);
        String code = "";
        if (redisUtils.mhasKey(vkey, vcode)) {
            code = redisUtils.mget(vkey, vcode).toString();
        }
        if (CheckUtils.isEmpty(code)) {
            throw new BusinessException(AcctErrorEnum.VCode_Expire);
        }
        if (!code.equals(vcode)) {
            throw new BusinessException(AcctErrorEnum.VCode_Error);
        }
        redisUtils.delete(vkey);
    }



    public BankCardInfo bankfour(BankCardInfo entity, LoginSimpleUserInfo userInfo) {
        BankFourReq req = new BankFourReq();
        req.setBankcard(entity.getCardNo());
        req.setIdcard(entity.getCardIdCard());
        req.setPhone(entity.getCardMobile());
        req.setRealname(entity.getCardUserName());
        BankFourResp resp = BankFourApi.bankFour_AppCode(bankFourApiConfig, req);
        if (ApiCallReturnCodeEnum.OK.getCode().equals(resp.getCode())) {
            entity.setAuthState(AcctConstant.AuthState.AUTH_SUCCESS.getCode());
            entity.setAuthType(AcctConstant.AuthType.ELEMENT.getCode());
            entity.setAuthDate(LocalDateTime.now());
            entity.setAuthUserId(userInfo.getId());
            entity.setAuthIp(userInfo.getIp());
            entity.setBankName(resp.getData().getBankname());
            entity.setCardName(resp.getData().getCardname());
            entity.setCardType(resp.getData().getCardtype());
        } else {
            entity.setAuthState(AcctConstant.AuthState.AUTH_FAIL.getCode());
        }
        entity.setAuthThirdState(resp.getCode());
        entity.setAuthThirdStateMemo(resp.getMsg());
        return entity;
    }



    private String getSmsContent(String vcode, AcctMsgSendTypeEnum sendType){
        String content = "验证码 {} (请勿告知他人)，该验证码是{}，10分钟有效。【太平经纪】";
        return StrUtil.format(content, vcode, sendType.getMsg());
    }


    private void checkSendLimit(Integer userId, String mobile) {
        String vkey = AccountCacheKeyUtils.getUserBankCardLimitKey(userId, mobile);
        int times = 0;
        long previousTime = 0;
        Map<String, Object> previousInfo = redisUtils.mget(vkey);
        if(previousInfo != null && !previousInfo.isEmpty()) {
            times = Integer.parseInt(previousInfo.get("times").toString());
            previousTime = Long.parseLong(previousInfo.get("updateTime").toString());
        }

        // 一分钟只能发一次
        long currentTime = System.currentTimeMillis() / 1000;
        if (currentTime - previousTime < 60) {
            throw new BusinessException(AcctErrorEnum.SMS_CAN_ONLY_BE_SENT_ONCE_PER_MINUTE);
        }

        // 一天最多20条
        if (times > 19) {
            throw new BusinessException(AcctErrorEnum.SMS_SEND_LIMIT);
        }

        Map<String, String> map = new HashMap<>();
        map.put("updateTime", String.valueOf(currentTime));
        map.put("times", String.valueOf(times + 1));
        Duration duration = Duration.between(LocalDateTime.now(), LocalDateTime.of(LocalDate.now(), LocalTime.MAX));
        System.out.println("duration:" + duration.getSeconds());
        redisUtils.mput(vkey, map, duration.getSeconds());
    }
}
